From Nand to Tetris week 1
这周开始学习From Nand to Tetris,中文名为“依据基本原理构建现代计算机:从与非门到俄罗斯方块”,课程介绍了计算机的工作原理,每周有一个项目,完成课程之后,可以真正构建出一个可以运行的计算机,课程也没有太多的先修课程,只要学过任何一门编程语言即可。
课程官网:
视频地址:
https://www.coursera.org/learn/build-a-computer
Chapter 1 布尔逻辑
Part 1:课程回顾
第一讲的内容比较基础,下面回顾几个重点部分:
Bool逻辑与Bool函数
课程首先介绍Bool逻辑的常用性质,这里假设我们只使用$\text{And,Not,Or}$操作。比较关键的一点是Bool表达式对应了真值表,例如
对应了
$x$ | $y$ | $z$ | $f$ |
---|---|---|---|
0 | 0 | 0 | 0 |
0 | 0 | 1 | 1 |
0 | 1 | 0 | 0 |
0 | 1 | 1 | 1 |
1 | 0 | 0 | 0 |
1 | 0 | 1 | 0 |
1 | 1 | 0 | 1 |
1 | 1 | 1 | 1 |
这部分表示Bool表达式$\Rightarrow$真值表,一个比较自然的问题是如何从真值表推出Bool表达式?
考虑如下例子:
$x$ | $y$ | $z$ | $f$ |
---|---|---|---|
0 | 0 | 0 | 1 |
0 | 0 | 1 | 0 |
0 | 1 | 0 | 1 |
0 | 1 | 1 | 0 |
1 | 0 | 0 | 1 |
1 | 0 | 1 | 0 |
1 | 1 | 0 | 0 |
1 | 1 | 1 | 0 |
构造方法很简单,首先考虑只在$f$取$1$的点处取$1$的表达式,例如此处为
然后将上述三个表达式取$\text{Or}$即得到目标表达式:
不难将上述方法推广到任意Bool表达式的构造,注意每个Bool函数可以用真值表表示,所以我们得到如下引理:
引理1
因为
所以实际上我们有更强的结论:
引理2
我们能否做的更好呢?不难看出在使用$\text{And,Not,Or}$的要求下,我们已经达到最优情形,因为$\text{Not}$无法表达$\text{And}$,反过来也是如此。但是如果可以使用别的逻辑操作,那么可以减少基础逻辑操作符的数量,考虑如下逻辑操作符$\text{Nand}$。
Nand门输入输出关系如下
$x$ | $y$ | $\text{Nand}(x,y)$ |
---|---|---|
$0$ | $0$ | $1$ |
$0$ | $1$ | $1$ |
$1$ | $0$ | $1$ |
$1$ | $1$ | $0$ |
即
不难验证
所以有如下定理:
定理
本课程中使用的基础逻辑操作为$\text{Nand}$。
HDL(Hardware description language)
本课程使用HDL编程语言来设计逻辑电路,具体的形式如下:
/** Xor gate: out = (a And Not(b)) Or (Not(a) And b)) */
CHIP Xor {
IN a, b;
OUT out;
PARTS:
// Implementation missing
}
具体的使用方法可以参考课本附录以及官网,注意HDL无法编译运行,但是可以使用老师提供的模拟器查看输入输出,这部分在视频中有详细介绍。
Part 2:项目
第一次项目使用Nand门构造常用的逻辑单元,推荐开发环境为VSCODE+Nand2Tetris插件。
芯片接口:
Nand
Nand门输入输出关系如下
$a$ | $b$ | $\text{Nand}(a,b)$ |
---|---|---|
$0$ | $0$ | $1$ |
$0$ | $1$ | $1$ |
$1$ | $0$ | $1$ |
$1$ | $1$ | $0$ |
Not
考虑$\text{Nand}(a,a)$
$a$ | $a$ | $\text{Nand}(a,a)$ |
---|---|---|
$0$ | $0$ | $1$ |
$0$ | $0$ | $1$ |
$1$ | $1$ | $0$ |
$1$ | $1$ | $0$ |
说明
And
$\text{Nand}(a,b)$的特点,不难发现有
Or
XOR
XOR门输入输出关系如下
$a$ | $b$ | $\text{XOR}(a,b)$ |
---|---|---|
$0$ | $0$ | $0$ |
$0$ | $1$ | $1$ |
$1$ | $0$ | $1$ |
$1$ | $1$ | $0$ |
所以有如下逻辑关系
Mux
Mux是选择器,输入为$a,b,\text{sel}$
$\text{sel}$ | $\text{out}$ |
---|---|
$0$ | $a$ |
$1$ | $b$ |
第一行相当于
第二行相当于
合并起来即为
DMux
DMux的作用如下:
- if (sel==0)
- {a,b}={in,0}
- else
- {a,b}={0,in}
真值表为
$\text{in}$ | $\text{sel}$ | $\text{Not}(\text{sel})$ | $a$ | $b$ |
---|---|---|---|---|
$0$ | $0$ | $1$ | $0$ | $0$ |
$0$ | $1$ | $0$ | $0$ | $0$ |
$1$ | $0$ | $1$ | $1$ | $0$ |
$1$ | $1$ | $0$ | $0$ | $1$ |
从真值表中,不难看出我们有
2020/9/20二刷更新:
逻辑关系其实很简单:
Not16
这个比较简单,只要对每一位取$\text{Not}$即可,注意这里没有循环。
And16
对$a[16]$与$b[16]$每一位取$\text{And}$即可。
OR16
利用
Mux16
根据$\text{sel}$对$a[16]$与$b[16]$每一位取$\text{Mux}$即可。
Or8Way
逐步计算下式即可
Mux4Way16
Mux4Way16的作用如下
- out = a if sel == 00
- b if sel == 01
- c if sel == 10
- d if sel == 11
所以可以根据$\text{sel}[0]$在$a,b$之间以及$c,d$之间做选择,然后根据$\text{sel}[1]$在第一步的结果之间做选择。
(备注,$\text{sel}[0]$为最右边的数字)
Mux8Way16
Mux8Way16和Mux4Way16作用类似,是对$8$个输入做选择,先根据$\text{sel}[0..1]$对前四个以及后四个做选择,然后根据$\text{sel}[2]$在第一步的结果之间做选择。
DMux4Way
- 4-way demultiplexor:
- {a, b, c, d} =
- {in, 0, 0, 0} if sel == 00
- {0, in, 0, 0} if sel == 01
- {0, 0, in, 0} if sel == 10
- {0, 0, 0, in} if sel == 11
第一步只考虑$\text{sel}[0]$,使用DMux产生如下效果
{a1, b1, c1, d1} =
- {in, 0, in, 0} if sel == 00
- {0, in, 0, in} if sel == 01
- {in, 0, in, 0} if sel == 10
- {0, in, 0, in} if sel == 11
对应代码如下
DMux (in=in, sel=sel[0], a=a1, b=b1);
DMux (in=in, sel=sel[0], a=c1, b=d1);
第二步考虑$\text{sel}[1]$,使用Mux产生如下效果
{a, b, c, d} =
- {in, 0, 0, 0} if sel == 00
- {0, in, 0, 0} if sel == 01
- {0, 0, in, 0} if sel == 10
- {0, 0, 0, in} if sel == 11
对应代码如下:
Not (in=sel[1], out=notsel1);
Mux (a=a1, b=notsel1, sel=sel[1], out=a);
Mux (a=b1, b=notsel1, sel=sel[1], out=b);
Mux (a=sel[1], b=c1, sel=sel[1], out=c);
Mux (a=sel[1], b=d1, sel=sel[1], out=d);
注意如下代码也可以:
Mux(a=a1, b=false, sel=sel[1], out=a);
Mux(a=b1, b=false, sel=sel[1], out=b);
Mux(a=false, b=c1, sel=sel[1], out=c);
Mux(a=false, b=d1, sel=sel[1], out=d);
DMux8Way
和DMux4Way一样的思路,分两步操作,根据$\text{sel}[0..1]$对$a,b,c,d$以及$e,f,g,h$用DMux4Way分别处理,然后利用根据$\text{sel}[2]$使用Mux处理。
DMux4Way(in=in, sel=sel[0..1], a=a1, b=b1, c=c1, d=d1);
DMux4Way(in=in, sel=sel[0..1], a=e1, b=f1, c=g1, d=h1);
Mux(a=a1, b=false, sel=sel[2], out=a);
Mux(a=b1, b=false, sel=sel[2], out=b);
Mux(a=c1, b=false, sel=sel[2], out=c);
Mux(a=d1, b=false, sel=sel[2], out=d);
Mux(a=false, b=e1, sel=sel[2], out=e);
Mux(a=false, b=f1, sel=sel[2], out=f);
Mux(a=false, b=g1, sel=sel[2], out=g);
Mux(a=false, b=h1, sel=sel[2], out=h);